#include "SmileStruct.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTH_LINGO 4
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace smileStructSpace {
  
  bool AlphabeticString(TNode <String> *NodeT, void* ref) {
    String* textA = NodeT->Info();
    String* textB = ((TNode <String>*)ref)->Info();
    return (*textA > *textB)?true:false;
  }

  bool EqualString(TNode <String> *NodeT, void* ref) {
    String* textA = NodeT->Info();
    String* textB = ((TNode <String>*)ref)->Info();
    return (*textA == *textB)?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct::SmileStruct() {
  this->code   = new String();
  this->id     = new String();
  this->info   = new String();
  this->lingos = new TListE <String> ();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct::SmileStruct(const char *code, const char *id) {
  this->code   = new String(code);
  this->id     = new String(id);
  this->info   = new String();
  this->lingos = new TListE <String> ();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct::SmileStruct(String* code, String* id) {
  this->code   = new String(code);
  this->id     = new String(id);
  this->info   = new String();
  this->lingos = new TListE <String> ();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct::SmileStruct(const SmileStruct&  smileStruct) {
  this->code   = new String(smileStruct.code);
  this->id     = new String(smileStruct.id);
  this->info   = new String(smileStruct.info);
  this->lingos = new TListE <String> (smileStruct.lingos);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct::SmileStruct(SmileStruct*  smileStruct) {
  this->code   = new String(smileStruct->code);
  this->id     = new String(smileStruct->id);
  this->info   = new String(smileStruct->info);
  this->lingos = new TListE <String> (smileStruct->lingos);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct::~SmileStruct() {
  if (this->code)   delete this->code;
  if (this->id)     delete this->id;
  if (this->info)   delete this->info;
  if (this->lingos) delete this->lingos;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Code(char* code) {
  if (!code)   this->code  = NULL;
  else       *(this->code) = code;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Code(String* code) {
  if (!code)   this->code  = NULL;
  else       *(this->code) = code->Out();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Id(char* id) {
  if (!id)   this->id  = NULL;
  else     *(this->id) = id;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Id(String* id) {
  if (!id)   this->id  = NULL;
  else     *(this->id) = id->Out();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Info(char* info) {
  if (!info)   this->info  = NULL;
  else       *(this->info) = info;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Info(String* info) {
  if (!info)   this->info  = NULL;
  else       *(this->info) = info->Out();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::Lingos(TListE <String>* lingos) {
  *(this->lingos) = *lingos;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SmileStruct::Code(void) {
  return this->code->Out();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SmileStruct::Id(void) {
  return this->id->Out();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SmileStruct::Info(void) {
  return this->info->Out();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SmileStruct::OutToSmileString(void) {
  
  if (!this->code || !this->id) return NULL;

  char *StringOut = new char[strlen(this->Code()) + strlen(this->Id()) + 2]; StringOut[0] = '\0';

  sprintf(StringOut, "%s %s\0", this->Code(), this->Id());

  StringOut[strlen(this->Code()) + strlen(this->Id()) + 1] = '\0';

  return StringOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SmileStruct::OutToSmileStringWithInfo(void) {

  if (!this->code || !this->id) return NULL;

  if (!this->info) {
    char *StringOut = new char[strlen(this->Code()) + strlen(this->Id()) + 2]; StringOut[0] = '\0';
    sprintf(StringOut, "%s %s\0", this->Code(), this->Id());
    StringOut[strlen(this->Code()) + strlen(this->Id()) + 1] = '\0';
    return StringOut;
  }
  else {
    char *StringOut = new char[strlen(this->Code()) + strlen(this->Id()) + strlen(this->Info()) + 3]; StringOut[0] = '\0';
    sprintf(StringOut, "%s %s %s\0", this->Code(), this->Id(), this->Info());
    StringOut[strlen(this->Code()) + strlen(this->Id()) + strlen(this->Info()) + 2] = '\0';
    return StringOut;
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* SmileStruct::Lingos() {
  return this->lingos;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::InputLine(String line) {

  char *part = strtok(line.Out(), " \n\r\t");
  if (!part) return;
  this->code->In(part);

  part = strtok(NULL, " \n\r\t");
  if (!part) return;
  this->id->In(part);

  part = strtok(NULL, " \n\r\t");
  while (part) {
    this->info->Add(part);
    this->info->Add(" ");
    part = strtok(NULL, " \n\r\t");
  }
  this->info->Add("\0");

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::InputLine(char* line) {

  char *part = strtok(line, " \n\r\t");
  if (!part) return;
  this->code->In(part);

  part = strtok(NULL, " \n\r\t");
  if (!part) return;
  this->id->In(part);

  part = strtok(NULL, " \n\r\t");
  while (part) {
    this->info->Add(part);
    this->info->Add(" ");
    part = strtok(NULL, " \n\r\t");
  }
  this->info->Add("\0");

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int SmileStruct::ObtainLingos(void) {

  String  temporal;
  char   *part     = NULL;

  temporal.In(this->Code());

  if (lingos->Length()) lingos->Clear();

  //Change of Cl and Br for L and R
  do {
    part = strstr(temporal.Out(),"Cl");
    if (part) strncpy(part,"L ",2);
  } while (part);

  do {
    part = strstr(temporal.Out(),"Br");
    if (part) strncpy(part,"R ",2);
  } while (part);

  int numberLingos = 0;
  for (int i = 0; i < temporal.Length(); i++)
    if (temporal[i] != ' ') temporal.In(temporal[i], numberLingos++);
  temporal.In('\0', numberLingos);
  numberLingos -= LENGTH_LINGO - 1;

  if (numberLingos) {
    for (int i = 0; i < numberLingos; i++)
      this->CopyLingo(temporal.Out(), i, i+4);
  }
  else {
    String *lingo = new String(temporal.Out());
    this->lingos->Add(lingo);
  }

  return this->lingos->Length();

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int SmileStruct::ObtainLingosWithoutNumber(void) {

  String  temporal;
  char   *part     = NULL;

  temporal.In(this->Code());
  
  if (lingos->Length()) lingos->Clear();

  //Change of Cl and Br for L and R
  do {
    part = strstr(temporal.Out(),"Cl");
    if (part) strncpy(part,"L ",2);
  } while (part);

  do {
    part = strstr(temporal.Out(),"Br");
    if (part) strncpy(part,"R ",2);
  } while (part);

  int numberLingos = 0;
  for (int i = 0; i < temporal.Length(); i++) {
    if (isdigit(temporal[i])) temporal.In('#', numberLingos);
    if (temporal[i] != ' ')   temporal.In(temporal[i], numberLingos++);
  }
  
  temporal.In('\0', numberLingos);
  numberLingos -= LENGTH_LINGO - 1;

  if (numberLingos) {
    for (int i = 0; i < numberLingos; i++)
      CopyLingo(temporal.Out(), i, i+4);
  }
  else {
    String *lingo = new String(temporal.Out());
    this->lingos->Add(lingo);
  }

  return this->lingos->Length();

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double SmileStruct::ObtainLingoSim(char *lingoString1, char *lingoString2) {

  long length1 = strlen(lingoString1), length2 = strlen(lingoString2);
  char tmpLingo1[length1 + 1], tmpLingo2[length2 + 1];
  long i, j, k, z;

  //Change the Cl by L and Br by R in the two lingo sequences
  long higher = ((length1 > length2)?length1:length2);
  
  for (i = 0, j = 0, k = 0; i < higher; i++) {
    if (i < length1) {
      if      (lingoString1[i] == 'l') tmpLingo1[j - 1] = 'L';
      else if (lingoString1[i] == 'r') tmpLingo1[j - 1] = 'R';
      else                             tmpLingo1[j++]   = lingoString1[i];
    }
    if (i < length2) {
      if      (lingoString2[i] == 'l') tmpLingo2[k - 1] = 'L';
      else if (lingoString2[i] == 'r') tmpLingo2[k - 1] = 'R';
      else                             tmpLingo2[k++]   = lingoString2[i];
    }
  }
  tmpLingo1[j] = '\0'; tmpLingo2[k] = '\0';

  j -= (LENGTH_LINGO - 1); k -= (LENGTH_LINGO - 1);
  long   L = j + k; //Total Lingos in two sequences
  double similarityValue = 0, Nai, Nbi;

  for (i = 0; i < j + k; i++) {

    char   compare[5];
    bool   analize = true;

    Nai = 0, Nbi = 0;

    if (i < j) {

      strncpy(compare, tmpLingo1 + i, 4);
      compare[4] = '\0';

      long zHigher = ((j > k)?j:k);

      for (z = 0; z < zHigher; z++) {
        if (z < j && !strncmp(compare, tmpLingo1 + z, 4)) {
          if (z < i) {
            analize = false;
            break;
          }
          Nai++;
        }
        else if (z < k && !strncmp(compare, tmpLingo2 + z, 4)) {
          Nbi++;
        }
      }
    }
    else {

      strncpy(compare, tmpLingo2 + i - j, 4);
      compare[4] = '\0';

      long zHigher = ((j > k)?j:k);

      for (z = 0; z < zHigher; z++) {
        if (z < j && !strncmp(compare, tmpLingo1 + z, 4)) {
          analize = false;
          break;
        }
        else if (z < k && !strncmp(compare, tmpLingo2 + z, 4)) {
          if (z < i - j) {
            analize = false;
            break;
          }
          Nbi++;
        }
      }
    }

    if (analize == true) similarityValue += (((Nai - Nbi) >= 0)?(1 - ((Nai - Nbi)/(Nai + Nbi))):(1 - ((Nbi - Nai)/(Nai + Nbi))));
    else                 L--;
  }

  return similarityValue/L;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double SmileStruct::ObtainLingoSimWithoutNumber(char *lingoString1, char *lingoString2) {

  long length1 = strlen(lingoString1), length2 = strlen(lingoString2);
  char tmpLingo1[length1 + 1], tmpLingo2[length2 + 1];
  long  i, j, k, z;

  //Change the Cl by L and Br by R in the two lingo sequences
  long higher = ((length1 > length2)?length1:length2);

  for (i = 0, j = 0, k = 0; i < higher; i++) {
    if (i < length1) {
      if      (lingoString1[i] == 'l')   tmpLingo1[j - 1] = 'L';
      else if (lingoString1[i] == 'r')   tmpLingo1[j - 1] = 'R';
      else if (isdigit(lingoString1[i])) tmpLingo1[j++]   = '#';
      else                               tmpLingo1[j++]   = lingoString1[i];
    }
    if (i < length2) {
      if      (lingoString2[i] == 'l')   tmpLingo2[k - 1] = 'L';
      else if (lingoString2[i] == 'r')   tmpLingo2[k - 1] = 'R';
      else if (isdigit(lingoString2[i])) tmpLingo2[k++]   = '#';
      else                               tmpLingo2[k++]   = lingoString2[i];
    }
  }
  tmpLingo1[j] = '\0'; tmpLingo2[k] = '\0';

  j -= (LENGTH_LINGO - 1); k -= (LENGTH_LINGO - 1);
  long   L = j + k; //Total Lingos in two sequences
  double similarityValue = 0, Nai, Nbi;

  for (i = 0; i < j + k; i++) {

    char   compare[5];
    bool   analize = true;

    Nai = 0, Nbi = 0;

    if (i < j) {

      strncpy(compare, tmpLingo1 + i, 4);
      compare[4] = '\0';

      long zHigher = ((j > k)?j:k);

      for (z = 0; z < zHigher; z++) {
        if (z < j && !strncmp(compare, tmpLingo1 + z, 4)) {
          if (z < i) {
            analize = false;
            break;
          }
          Nai++;
        }
        else if (z < k && !strncmp(compare, tmpLingo2 + z, 4)) {
          Nbi++;
        }
      }
    }
    else {

      strncpy(compare, tmpLingo2 + (i - j), 4);
      compare[4] = '\0';

      long zHigher = ((j > k)?j:k);

      for (z = 0; z < zHigher; z++) {
        if (z < j && !strncmp(compare, tmpLingo1 + z, 4)) {
          analize = false;
          break;
        }
        else if (z < k && !strncmp(compare, tmpLingo2 + z, 4)) {
          if (z < i - j) {
            analize = false;
            break;
          }
          Nbi++;
        }
      }
    }

    if (analize == true) similarityValue += (((Nai - Nbi) >= 0)?(1 - ((Nai - Nbi)/(Nai + Nbi))):(1 - ((Nbi - Nai)/(Nai + Nbi))));
    else                 L--;
  }

  return similarityValue/L;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double SmileStruct::ComputeLingoSimilarity(SmileStruct* smileStruct) {
  
  return this->ObtainLingoSim(smileStruct->code->Out(), this->code->Out());
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double SmileStruct::ComputeLingoSimilarity(SmileStruct& smileStruct) {

  return this->ObtainLingoSim(smileStruct.code->Out(), this->code->Out());

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double SmileStruct::ComputeLingoSimilarityWithoutNumber(SmileStruct* smileStruct) {

  return this->ObtainLingoSimWithoutNumber(smileStruct->code->Out(), this->code->Out());

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double SmileStruct::ComputeLingoSimilarityWithoutNumber(SmileStruct& smileStruct) {

  return this->ObtainLingoSimWithoutNumber(smileStruct.code->Out(), this->code->Out());

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ComputeLingoSimilarity(SmileStruct& smileStruct1, SmileStruct& smileStruct2) {
	
  double similarityValue = 0;

  if (!smileStruct1.lingos->Length()) {
    if (!smileStruct1.Code()) return -1;
    smileStruct1.ObtainLingos();
  }
  if (!smileStruct2.lingos->Length()) {
    if (!smileStruct2.Code()) return -1;
    smileStruct2.ObtainLingos();
  }

  TListE <String>* totalLingos = new TListE <String> ();

  smileStruct1.lingos->SetInitial();
  while (smileStruct1.lingos->SetNext()) {
    String *totalLingo = new String(smileStruct1.lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  smileStruct2.lingos->SetInitial();
  while (smileStruct2.lingos->SetNext()) {
    String *totalLingo = new String(smileStruct2.lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  totalLingos->QuickSortList(smileStructSpace::AlphabeticString, NULL);
  totalLingos->CompactListAfterOrdered(smileStructSpace::EqualString, NULL);
  int L = totalLingos->Length();

  totalLingos->SetInitial();

  for (int i = 0; i < L; i++)	{
    double Nai = smileStruct1.lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetNextNode());
    double Nbi = smileStruct2.lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetCurrentNode());
    if ((Nai - Nbi) >= 0) similarityValue += (1 - (double)((Nai - Nbi)/(Nai + Nbi)));
    if ((Nbi - Nai) >  0) similarityValue += (1 - (double)((Nbi - Nai)/(Nai + Nbi)));
  }
  similarityValue /= L;

  if (totalLingos) delete totalLingos;

  return similarityValue;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ComputeLingoSimilarity(SmileStruct* smileStruct1, SmileStruct* smileStruct2) {
	
  double similarityValue = 0;

  if (!smileStruct1->lingos->Length()) {
    if (!smileStruct1->Code()) return -1;
    smileStruct1->ObtainLingos();
  }
  if (!smileStruct2->lingos->Length()) {
    if (!smileStruct2->Code()) return -1;
    smileStruct2->ObtainLingos();
  }

  TListE <String>* totalLingos = new TListE <String> ();

  smileStruct1->lingos->SetInitial();
  while (smileStruct1->lingos->SetNext()) {
    String *totalLingo = new String(smileStruct1->lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  smileStruct2->lingos->SetInitial();
  while (smileStruct2->lingos->SetNext()) {
    String *totalLingo = new String(smileStruct2->lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  totalLingos->QuickSortList(smileStructSpace::AlphabeticString, NULL);
  totalLingos->CompactListAfterOrdered(smileStructSpace::EqualString, NULL);
  int L = totalLingos->Length();

  totalLingos->SetInitial();

  for (int i = 0; i < L; i++)	{
    double Nai = smileStruct1->lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetNextNode());
    double Nbi = smileStruct2->lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetCurrentNode());
    if ((Nai - Nbi) >= 0) similarityValue += (1 - (double)((Nai - Nbi)/(Nai + Nbi)));
    if ((Nbi - Nai) >  0) similarityValue += (1 - (double)((Nbi - Nai)/(Nai + Nbi)));
  }
  similarityValue /= L;

  if (totalLingos) delete totalLingos;

  return similarityValue;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ComputeLingoSimilarityWithoutNumber(SmileStruct& smileStruct1, SmileStruct& smileStruct2) {

  double similarityValue = 0;

  if (!smileStruct1.lingos->Length()) {
    if (!smileStruct1.Code()) return -1;
    smileStruct1.ObtainLingosWithoutNumber();
  }
  if (!smileStruct2.lingos->Length()) {
    if (!smileStruct2.Code()) return -1;
    smileStruct2.ObtainLingosWithoutNumber();
  }

  TListE <String>* totalLingos = new TListE <String> ();

  smileStruct1.lingos->SetInitial();
  while (smileStruct1.lingos->SetNext()) {
    String *totalLingo = new String(smileStruct1.lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  smileStruct2.lingos->SetInitial();
  while (smileStruct2.lingos->SetNext()) {
    String *totalLingo = new String(smileStruct2.lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  totalLingos->QuickSortList(smileStructSpace::AlphabeticString, NULL);
  totalLingos->CompactListAfterOrdered(smileStructSpace::EqualString, NULL);
  int L = totalLingos->Length();

  totalLingos->SetInitial();

  for (int i = 0; i < L; i++)	{
    double Nai = smileStruct1.lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetNextNode());
    double Nbi = smileStruct2.lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetCurrentNode());
    if ((Nai - Nbi) >= 0) similarityValue += (1 - (double)((Nai - Nbi)/(Nai + Nbi)));
    if ((Nbi - Nai) >  0) similarityValue += (1 - (double)((Nbi - Nai)/(Nai + Nbi)));
  }
  similarityValue /= L;

  if (totalLingos) delete totalLingos;

  return similarityValue;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ComputeLingoSimilarityWithoutNumber(SmileStruct* smileStruct1, SmileStruct* smileStruct2) {

  double similarityValue = 0;

  if (!smileStruct1->lingos->Length()) {
    if (!smileStruct1->Code()) return -1;
    smileStruct1->ObtainLingosWithoutNumber();
  }
  if (!smileStruct2->lingos->Length()) {
    if (!smileStruct2->Code()) return -1;
    smileStruct2->ObtainLingosWithoutNumber();
  }

  TListE <String>* totalLingos = new TListE <String> ();

  smileStruct1->lingos->SetInitial();
  while (smileStruct1->lingos->SetNext()) {
    String *totalLingo = new String(smileStruct1->lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  smileStruct2->lingos->SetInitial();
  while (smileStruct2->lingos->SetNext()) {
    String *totalLingo = new String(smileStruct2->lingos->GetCurrent());
    totalLingos->Add(totalLingo);
  }

  totalLingos->QuickSortList(smileStructSpace::AlphabeticString, NULL);
  totalLingos->CompactListAfterOrdered(smileStructSpace::EqualString, NULL);
  int L = totalLingos->Length();

  totalLingos->SetInitial();

  for (int i = 0; i < L; i++)	{
    double Nai = smileStruct1->lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetNextNode());
    double Nbi = smileStruct2->lingos->NumberOcurrence(smileStructSpace::EqualString, totalLingos->GetCurrentNode());
    if ((Nai - Nbi) >= 0) similarityValue += (1 - (double)((Nai - Nbi)/(Nai + Nbi)));
    if ((Nbi - Nai) >  0) similarityValue += (1 - (double)((Nbi - Nai)/(Nai + Nbi)));
  }
  similarityValue /= L;

  if (totalLingos) delete totalLingos;

  return similarityValue;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SmileStruct::CopyLingo(char* line, int start, int end) {

  String *lingo = new String();
  for (int i = start; i < end; i++) lingo->Add(line[i]);
  this->lingos->Add(lingo);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SmileStruct SmileStruct::operator=(const SmileStruct& smileStruct) {

  if (smileStruct.code) *(this->code) = *(smileStruct.code);
  if (smileStruct.id)   *(this->id)   = *(smileStruct.id);
  if (smileStruct.info) *(this->info) = *(smileStruct.info);

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SmileStruct::operator==(const SmileStruct& smileStruct) {

  return (*(this->code) == *(smileStruct.code)) && (*(this->id) == *(smileStruct.id));

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SmileStruct::operator!=(const SmileStruct& smileStruct) {

  return (*(this->code) != *(smileStruct.code)) || (*(this->id) != *(smileStruct.id));

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
